use crate::client::error::GrpcClientError;
use crate::client::retry_policy::RetryPolicy;
use std::future::Future;
use std::pin::Pin;
use tracing::warn;

pub struct RetryExecutor {
    policy: RetryPolicy,
}

/// 判断是否为网络错误
impl RetryExecutor {
    pub fn new(policy: RetryPolicy) -> Self {
        Self { policy }
    }

    /// 执行带有重试策略的操作
    pub async fn execute_with_retry<F, T, E>(&self, operation: F) -> Result<T, GrpcClientError>
    where
        F: Fn() -> Pin<Box<dyn Future<Output = Result<T, E>>>>,
        E: Into<GrpcClientError>,
    {
        let mut attempt = 1;

        loop {
            match operation().await {
                Ok(result) => return Ok(result),
                Err(error) => {
                    let client_error: GrpcClientError = error.into();

                    if !self.policy.is_network_error(&client_error)
                        || attempt >= self.policy.max_attempts
                    {
                        return Err(client_error);
                    }

                    let delay = self.policy.calculate_delay(attempt);
                    warn!("操作失败，第 {} 次重试，等待 {:?}", attempt, delay);
                    tokio::time::sleep(delay).await;

                    attempt += 1;
                }
            }
        }
    }
}
